package org.doc.core.api.jfinal;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.doc.bean.Api;
import org.doc.bean.ApiAction;
import org.doc.bean.ApiRequestParam;
import org.doc.bean.ApiResponseParam;
import org.doc.core.api.AbstractApiParser;
import org.doc.core.constant.Constant;
import org.doc.utils.ClassUtils;

import com.jfinal.aop.Before;
import com.jfinal.aop.Interceptor;
import com.jfinal.core.ActionKey;
import com.jfinal.core.Controller;
import com.jfinal.ext.interceptor.GET;
import com.jfinal.ext.interceptor.POST;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.Tag;

/**
 * JFinal解析器
 *
 */
public class JFinalApiParser extends AbstractApiParser {

    @Override
    public List<String> filterController(List<String> fileNames) {
        List<String> controllerFileNames = new ArrayList<String>();
        for (String fileName : fileNames) {
            String packageFileName = fileName.substring(Constant.JAVA_FILE_PATH.length(), fileName.length() - Constant.JAVA_FILE_SUFFIX.length()).replace(File.separator, ".");
            try {
                Class<?> fileClass = Class.forName(packageFileName);
                if (fileClass.newInstance() instanceof Controller) {
                    controllerFileNames.add(fileName);
                }
            } catch (Exception e) {

            }
        }
        return controllerFileNames;
    }

    @Override
    public List<Api> generateApi(ClassDoc[] classDocs) {
        List<Api> apis = new ArrayList<Api>();
        for (ClassDoc classDoc : classDocs) {

            Api api = new Api();
            api.setTitle(classDoc.commentText());

            MethodDoc[] methodDocs = classDoc.methods(false);

            Class<?> controllerClass = null;
            try {
                controllerClass = Class.forName(classDoc.qualifiedTypeName());
            } catch (ClassNotFoundException e) {

            }

            String url = JFinalApiDocConfig.getControllerKey(classDoc.name());

            List<ApiAction> apiActions = new ArrayList<ApiAction>(methodDocs.length);

            for (MethodDoc methodDoc : methodDocs) {

                ApiAction apiAction = new ApiAction();

                Class<?>[] paramTypes = null;
                Method method = null;
                try {
                    paramTypes = ClassUtils.getParamTypes(methodDoc);
                    method = controllerClass.getDeclaredMethod(methodDoc.name(), paramTypes);
                } catch (Exception e) {

                }
                Tag[] tags = methodDoc.tags();

                List<ApiRequestParam> apiRequestParams = generateApiReqeustParam(tags);
                List<ApiResponseParam> apiResponseParams = generateApiResponseParam(tags);
                String title = getTitle(tags);
                String respBody = getRespBody(tags);
                String requestUrl = generateRequestUrl(method, url);
                String requestType = getRequestType(method);

                apiAction.setRequestType(requestType);
                apiAction.setTitle(title);
                apiAction.setRespText(respBody);
                apiAction.setRespParams(apiResponseParams);
                apiAction.setReqParams(apiRequestParams);
                apiAction.setUrl(requestUrl);
                apiAction.setDesc(methodDoc.commentText());
                apiActions.add(apiAction);
            }

            api.setApiActions(apiActions);
            apis.add(api);
        }
        return apis;
    }

    private String generateRequestUrl(Method method, String parentUrl) {

        ActionKey actionKey = method.getAnnotation(ActionKey.class);

        if (actionKey == null) {
            return parentUrl + "/" + method.getName();
        }

        return actionKey.value();

    }

    private String getRequestType(Method method) {
        StringBuilder requestType = new StringBuilder();
        Before before = method.getAnnotation(Before.class);
        if (before != null) {
            Class<? extends Interceptor>[] classes = before.value();
            for(Class<? extends Interceptor> interceptor:classes){
                  if(interceptor==POST.class){
                      requestType.append(Constant.POST).append(",");
                  };
                  if(interceptor==GET.class){
                      requestType.append(Constant.GET).append(",");
                  };
            }
        }
        
        if (requestType.length() > 0) {
            return requestType.substring(0, requestType.length() - 1);
        }
        
        return Constant.POST+","+Constant.GET;
    }

}
